﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Aurora.Domain;
using Aurora.Infrastructure;
using Aurora.Infrastructure.IOC;
using Microsoft.Practices.Unity;

namespace Aurora.DataAccess
{
    /// <summary>
    /// Проверяет существование БД и её валидность.
    /// </summary>
    public class DbValidator : IDbValidator
    {
        private readonly AuroraEntities _entities;
        private readonly IUnityContainer _unityContainer;
        private bool _disposed;

        public DbValidator()
        {
            _entities = new AuroraEntities();
            _unityContainer = IocFabric.CreateConfigured("workingModel");
        }

        /// <summary>
        /// Проверка существования БД.
        /// </summary>
        /// <returns>
        /// Логическое значение успешности операции.
        /// </returns>
        public bool IsDbExist()
        {
            return _entities.Database.Exists();
        }

        /// <summary>
        /// Создает новую БД из схемы EntityFramework.
        /// </summary>
        /// <returns>
        /// Логическое значение успешности операции.
        /// </returns>
        public bool CreateDb()
        {
            try
            {
                _entities.Database.CreateIfNotExists();
                return true;
            }
            catch (Exception)
            {
                Messenger.ShowErrorMessage("Ошибка при создании БД",
                                           "Проверьте наличие необходимых прав доступа.");
                return false;
            }
        }

        /// <summary>
        /// Проверка соответствия БД и модели сущностей EntityFramework
        /// </summary>
        /// <returns>
        /// Логическое значение успешности операции.
        /// </returns>
        public bool CheckModel()
        {
            bool isValid;

            try
            {
                _entities.Database.CompatibleWithModel(true);
                isValid = true;
            }
            catch(Exception)
            {
                isValid = false;
            }

            return isValid;
        }

        /// <summary>
        /// Инициализация базы данных согласно модели EF CodeFirst
        /// </summary>
        public void InitDb()
        {
            if (IsDbExist())
            {
                if(CheckModel())
                {
                    return;
                }
                else
                {
                    try
                    {
                        File.Copy("Aurora.sdf", "Aurora.old", true);
                        _entities.Database.Delete();
                    }
                    catch (Exception)
                    {
                        Messenger.ShowExclamation("");
                    }
                }
            }

            CreateDb();
            return;
        }

        /// <summary>
        /// Слияние локальной и главной БД. Обновляет/добавляет записи в главную БД.
        /// </summary>
        /// <returns>
        /// Логическое значение успешности операции.
        /// </returns>
        public bool MergeDb()
        {
            if (!IsDbExist())
            {
                Messenger.ShowErrorMessage("Ошибка при слиянии БД",
                                           "Отсутствуют записи в локальной БД.");
                return false; 
            }

            var localCards = new List<ClientCard>(_entities.ClientCards);
            var repository = _unityContainer.Resolve<IRepository>();

            _entities.Database.Connection.ChangeDatabase("ServerDataBase");
            _entities.Database.Initialize(false);

            foreach (var localCard in localCards)
            {
                var existCard = _entities.ClientCards.Single(t => t == localCard);
                if(existCard == null) continue;
                repository.Update(existCard, localCard);
            }

            repository.SubmitChanges();
            repository.Dispose();

            return true;
        }

        #region Implementation of IDisposable

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    _entities.Dispose();
                    _unityContainer.Dispose();
                }
                
                _disposed = true;
            }
        }
        #endregion
    }
}
